<!doctype html>
<html>
  <head>
    <title>ADK MCP App - Alternating Messages (Debug)</title>
    <style>
      /* CSS Styles remain the same as the previous 'alternating' version */
      /* Apply Arial font to the whole page */
      body {
        font-family: Arial, sans-serif;
        line-height: 1.6;
      }

      /* Style for the header container (logo + title) */
      .header-container {
        display: flex;
        align-items: center;
        margin-bottom: 1em;
      }

      /* Style for the logo image */
      .logo {
        height: 40px;
        width: auto;
        margin-right: 15px;
      }

      /* Style for the main heading */
      .header-container h1 {
        margin: 0;
      }

      #sendButton {
        background-color: #28a745;
        color: white;
        border: none;
        padding: 6px 12px;
        border-radius: 4px;
        cursor: pointer;
        font-weight: bold;
      }

      #sendButton:hover:not(:disabled) {
        background-color: #218838;
      }

      #sendButton:disabled {
        background-color: #a3d9b1;
        color: #f0f0f0;
        cursor: not-allowed;
      }

      #messages {
        height: 800px;
        overflow-y: auto;
        border: 1px solid #ccc;
        padding: 10px;
        background-color: #f9f9f9;
        /* Add some spacing between messages */
        display: flex;
        flex-direction: column;
        gap: 0.5em;
      }

      /* Remove default margins from paragraphs inside messages */
      #messages p {
        margin: 0;
        /* Resetting margins */
      }

      /* Style for user messages */
      #messages p.user-message {
        color: #0056b3;
        background-color: #e7f3ff;
        padding: 8px 8px 8px 12px;
        border-radius: 5px;
        position: relative;
        align-self: flex-end;
        /* Align user messages to the right */
        max-width: 80%;
        /* Optional: limit width */
        word-wrap: break-word;
        /* Ensure long words break */
      }

      /* Add human icon and [User] prefix */
      #messages p.user-message::before {
        content: "👤 [User]: ";
        /* Added space */
        font-weight: bold;
        margin-right: 5px;
        /* Reduced margin */
      }

      /* Base style for server messages container (agent responses AND system status) */
      #messages p.server-message-block {
        color: #020202;
        padding: 8px 8px 8px 12px;
        background-color: #fff;
        border: 1px solid #eee;
        border-radius: 5px;
        position: relative;
        align-self: flex-start;
        /* Align server messages to the left */
        max-width: 80%;
        /* Optional: limit width */
        word-wrap: break-word;
        /* Ensure long words break */
      }

      /* Add robot icon ONLY to server messages that are NOT system status messages */
      #messages p.server-message-block:not(.system-status-message)::before {
        content: "🤖[Agent]: ";
        /* Robot emoji */
        font-weight: bold;
        margin-right: 8px;
        /* Space between icon and message content */
        display: inline-block;
        /* Helps with alignment */
        vertical-align: top;
        /* Align icon with the top of the text block */
        float: left;
        /* Float icon left */
      }

      /* Adjust content padding for server messages with icon */
      #messages p.server-message-block:not(.system-status-message) {
        padding-left: 30px;
        /* Make space for the floated icon */
      }

      /* Specific styles for system status messages (they still use server-message-block for base style) */
      #messages p.system-status-message {
        /* Center align system messages and use full width */
        align-self: center;
        max-width: 100%;
        text-align: center;
        font-style: italic;
        color: #555;
        background-color: #f0f0f0;
        /* Slightly different background */
        border: none;
        padding-left: 12px;
        /* Reset padding */
      }

      /* Keep specific color styles using spans inside the p tags */
      .connection-open-text {
        color: green;
        font-weight: bold;
      }

      .connection-closed-text {
        color: orange;
        font-weight: bold;
      }

      .error-text {
        color: red;
        font-weight: bold;
      }

      /* Basic Markdown styling */
      #messages code {
        background-color: #eee;
        padding: 2px 4px;
        border-radius: 3px;
        font-family: monospace;
        word-wrap: break-word;
      }

      #messages pre {
        background-color: #eee;
        padding: 10px;
        border-radius: 3px;
        overflow-x: auto;
        max-width: 100%;
        /* Ensure pre doesn't overflow container */
      }

      #messages blockquote {
        border-left: 3px solid #ccc;
        padding-left: 10px;
        margin-left: 0;
        color: #555;
      }

      #messages ul,
      #messages ol {
        margin-left: 20px;
        /* Keep indentation */
        padding-left: 0;
        /* Fix potential layout issues with floated icon */
        overflow: hidden;
      }

      /* Ensure Markdown elements inside server messages don't disrupt the icon float */
      #messages .server-message-block > *:first-child {
        /* No longer needed with float */
      }

      #messages .server-message-block > pre:first-child,
      #messages .server-message-block > ul:first-child,
      #messages .server-message-block > ol:first-child,
      #messages .server-message-block > blockquote:first-child {
        /* No longer needed */
      }
    </style>
    <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
  </head>

  <body>
    <div class="header-container">
      <img
        src="https://google.github.io/adk-docs/assets/agent-development-kit.png"
        alt="ADK Logo"
        class="logo"
        title="Agent Development Kit" />
      <h1>ADK Agent Integrated with MCP</h1>
    </div>

    <div id="messages"></div>
    <br />

    <form id="messageForm">
      <label for="message">Message:</label>
      <input type="text" id="message" name="message" style="width: 80%" />
      <button type="submit" id="sendButton" disabled>Send</button>
    </form>
  </body>

  <script>
    // Wrap everything in DOMContentLoaded to ensure elements exist
    document.addEventListener("DOMContentLoaded", (event) => {
      console.log("DOM fully loaded and parsed");

      // --- DOM Elements ---
      const messageForm = document.getElementById("messageForm");
      const messageInput = document.getElementById("message");
      const messagesDiv = document.getElementById("messages");
      const sendButton = document.getElementById("sendButton");

      // --- Check if elements were found ---
      if (!messageForm || !messageInput || !messagesDiv || !sendButton) {
        console.error(
          "CRITICAL: One or more required DOM elements not found! Check IDs.",
        );
        alert("Initialization Error: UI elements missing. App cannot start.");
        // Add visual error in the message area if possible
        if (messagesDiv) {
          messagesDiv.innerHTML =
            "<p class='server-message-block system-status-message'><span class='error-text'>Initialization Error: UI elements missing.</span></p>";
        }
        return; // Stop script execution
      }
      console.log("UI Elements successfully located.");

      // --- WebSocket Connection Setup ---
      const sessionId = Math.random().toString().substring(10);
      const ws_url = "ws://" + window.location.host + "/ws/" + sessionId;
      let ws = null; // Initialize ws to null
      let reconnectAttempts = 0;
      const maxReconnectAttempts = 5; // Limit reconnect attempts

      // --- Add Status Message Helper ---
      function addStatusMessage(text, typeClass) {
        if (!messagesDiv) {
          console.error("Cannot add status message, messagesDiv not found");
          return;
        }
        try {
          const p = document.createElement("p");
          p.classList.add("server-message-block", "system-status-message");
          const span = document.createElement("span");
          span.className = typeClass; // e.g., 'error-text', 'connection-open-text'
          span.textContent = text;
          p.appendChild(span);
          messagesDiv.appendChild(p);
          messagesDiv.scrollTop = messagesDiv.scrollHeight;
        } catch (e) {
          console.error("Error adding status message:", e);
        }
      }

      // --- WebSocket Handlers ---
      function addWebSocketHandlers(webSocketInstance) {
        // Clear previous handlers to prevent duplicates on reconnect
        webSocketInstance.onopen = null;
        webSocketInstance.onmessage = null;
        webSocketInstance.onclose = null;
        webSocketInstance.onerror = null;
        console.log("Cleared previous WebSocket handlers.");

        webSocketInstance.onopen = function () {
          console.log("WebSocket connection opened successfully.");
          reconnectAttempts = 0; // Reset reconnect attempts on successful open
          try {
            if (sendButton) {
              sendButton.disabled = false;
              console.log("Send button ENABLED.");
            } else {
              console.error("Send button element not found in onopen!");
            }
            addStatusMessage("Connection opened", "connection-open-text");
            // Attach the submit handler *only* when connection is open
            addSubmitHandler(this);
            console.log("Submit handler attached.");
          } catch (error) {
            console.error("Error during WebSocket onopen execution:", error);
            addStatusMessage(
              `Error during connection setup: ${error.message}`,
              "error-text",
            );
            if (sendButton) sendButton.disabled = true; // Ensure button is disabled if error occurs
          }
        };

        webSocketInstance.onmessage = function (event) {
          // console.log("Received raw data:", event.data); // Keep for debug if needed
          try {
            const packet = JSON.parse(event.data);
            // console.log("Received parsed packet:", packet); // Keep for debug

            if (packet.turn_complete && packet.turn_complete === true) {
              console.log("Turn complete signal received.");
              return;
            }

            if (packet.message) {
              const messageElement = document.createElement("p");
              messageElement.classList.add("server-message-block");

              try {
                const htmlContent = marked.parse(packet.message);
                messageElement.innerHTML = htmlContent;
              } catch (e) {
                console.error("Error parsing Markdown:", e);
                const textNode = document.createTextNode(packet.message);
                messageElement.appendChild(textNode);
                addStatusMessage(
                  `Markdown parsing error: ${e.message}`,
                  "error-text",
                );
              }

              if (messagesDiv) {
                messagesDiv.appendChild(messageElement);
                // console.log("Added new server message block."); // Less verbose logging
                messagesDiv.scrollTop = messagesDiv.scrollHeight;
              } else {
                console.error("Messages container not found in onmessage!");
              }
            } else {
              console.log("Received packet without 'message' field:", packet);
            }
          } catch (parseError) {
            console.error(
              "Error parsing incoming WebSocket message:",
              parseError,
              "Raw data:",
              event.data,
            );
            addStatusMessage(
              `Error processing server message: ${parseError.message}`,
              "error-text",
            );
          }
        };

        webSocketInstance.onclose = function (event) {
          console.warn(
            `WebSocket connection closed. Code: ${event.code}, Reason: '${
              event.reason || "No reason given"
            }', Was Clean: ${event.wasClean}`,
          );
          if (sendButton) {
            sendButton.disabled = true;
            console.log("Send button DISABLED due to close.");
          }
          // Remove submit handler when connection is closed
          if (messageForm) messageForm.onsubmit = null;

          if (reconnectAttempts < maxReconnectAttempts) {
            reconnectAttempts++;
            const reconnectDelay = 5000 * reconnectAttempts; // Exponential backoff (simple version)
            addStatusMessage(
              `Connection closed. Attempting reconnect ${reconnectAttempts}/${maxReconnectAttempts} in ${
                reconnectDelay / 1000
              }s...`,
              "connection-closed-text",
            );
            setTimeout(connectWebSocket, reconnectDelay); // Use the dedicated connect function
          } else {
            console.error("Max reconnection attempts reached. Giving up.");
            addStatusMessage(
              "Connection lost. Max reconnection attempts reached. Please reload the page.",
              "error-text",
            );
          }
        };

        webSocketInstance.onerror = function (error) {
          // Note: 'onerror' sends a simple Event object, not usually detailed error info
          console.error("WebSocket error occurred:", error);
          // Add a generic error message. 'onclose' will usually follow immediately and provide more details/handle reconnect.
          addStatusMessage(
            "WebSocket error occurred. Check console.",
            "error-text",
          );
          // Do not disable button here, onclose will handle it.
        };

        console.log(
          "WebSocket event handlers attached for:",
          webSocketInstance.url,
        );
      }

      // --- Form Submit Handler ---
      // Defined outside addWebSocketHandlers so it's created only once
      function submitMessageHandler(e) {
        e.preventDefault(); // Always prevent default

        if (!ws || ws.readyState !== WebSocket.OPEN) {
          console.warn(
            "Attempted to send message, but WebSocket is not open. State:",
            ws ? ws.readyState : "null",
          );
          addStatusMessage(
            "Cannot send message - Connection is not active.",
            "error-text",
          );
          return false;
        }

        const messageText = messageInput.value.trim();
        if (messageText && messagesDiv && messageInput) {
          const p = document.createElement("p");
          p.textContent = messageText; // Use textContent for safety
          p.classList.add("user-message");
          messagesDiv.appendChild(p);
          messagesDiv.scrollTop = messagesDiv.scrollHeight;

          try {
            console.log("Sending message:", messageText);
            ws.send(messageText);
          } catch (error) {
            console.error("Error sending message via WebSocket:", error);
            addStatusMessage(
              `Failed to send message: ${error.message}`,
              "error-text",
            );
            // Optionally add visual indication to the user message itself
            const errorSpan = document.createElement("span");
            errorSpan.textContent = " (Send Error)";
            errorSpan.style.color = "red";
            errorSpan.style.fontWeight = "normal";
            p.appendChild(errorSpan);
          }
          messageInput.value = ""; // Clear input field
        } else if (!messageText) {
          console.log("Empty message submission ignored.");
        }
        return false; // Prevent default form submission behavior
      }

      // Function to attach the single submit handler instance
      // Now called only from ws.onopen
      function addSubmitHandler() {
        if (messageForm) {
          messageForm.onsubmit = submitMessageHandler;
          console.log("Submit handler assigned to form.");
        } else {
          console.error(
            "Message form not found, cannot assign submit handler!",
          );
        }
      }

      // --- Initial Connection Function ---
      function connectWebSocket() {
        console.log(
          `Attempting to connect to WebSocket: ${ws_url} (Attempt: ${
            reconnectAttempts + 1
          })`,
        );
        // addStatusMessage(`Connecting to server... (Attempt ${reconnectAttempts + 1})`, "connection-closed-text"); // Use orange for connecting status
        try {
          ws = new WebSocket(ws_url); // Create the WebSocket instance
          addWebSocketHandlers(ws); // Attach handlers to the new instance
        } catch (error) {
          console.error("Error creating WebSocket object:", error);
          addStatusMessage(
            `Failed to initialize connection: ${error.message}`,
            "error-text",
          );
          // Attempt reconnect after delay if creation fails
          if (reconnectAttempts < maxReconnectAttempts) {
            reconnectAttempts++;
            const reconnectDelay = 5000 * reconnectAttempts;
            setTimeout(connectWebSocket, reconnectDelay);
          } else {
            addStatusMessage(
              "Failed to initialize connection after multiple attempts.",
              "error-text",
            );
          }
        }
      }

      // --- Start the application ---
      console.log("Starting WebSocket application...");
      connectWebSocket(); // Initial connection attempt
    }); // End DOMContentLoaded
  </script>
</html>
